|
|
EMG - Overview |
| Tags | other☁overview☁emg |
The action of skeletal muscles for movement and postural control is voluntary, causing drastic differences in EMG signal when comparing to ECG, namely the inexistence of natural periodicity.
For contracting a muscle , a large set of motor units needs to be activated, so that the acquired EMG signal is the sum of their elementary potential changes. Because of this "summation" process, EMG seems to be a little "anarchic", and the essence of EMG signal processing is in study the activation zones .
This Jupyter Notebook provides an overview on the processing steps to be taken into account for EMG signal processing for the extraction of parameters as well as event detection. It implies simple techniques, which can be extended with more complex processing methods.
The following topics will be covered:
Importing relevant packages
# Biosignalsnotebooks python package
import biosignalsnotebooks as bsnb
# Scientific packages
from numpy import max, min, average, std, sum, sqrt, where, argmax, absolute, array, random, zeros
from scipy.integrate import cumtrapz
from scipy.signal import welch
A.2 - Selection of a bone structure away from the active muscles: Clavicle
|
| Ground electrode on clavicle |
B. Acquisition
B.1 - Sampling Rate:In the following images, we can see the effect of sampling rate choice. EMG muscular activation was collected at 10 Hz and at 1000 Hz .
Observation of different sampling frequencies:
For more information on sampling rate see
Jupyter Notebook
entitled
"Problems of low sampling rate (aliasing)"
B.2 - Resolution:
Resolution is another parameter that must be configured prior to acquisition. For PLUX acquisition systems, that support acquisitions with resolutions between 6 ( bitalino ) and 16 bits, a smaller resolution may not cause easily observable changes in EMG or ECG, as we will see in the following images by comparing the same signal when acquired with distinct resolutions.
EMG muscular activation was collected at 8 Bit and 16 Bit with a sampling frequency of 1000 Hz .
Observation about different resolutions at 1000 Hz:
The signal shows a slight difference when comparing the same signal with
8 Bit
, where the signal is slightly more angular and
16 Bit
, where the signal is slightly more round.
However in some cases, such as temperature monitoring see
Jupyter Notebook
entitled
"Resolution - The difference between smooth and abrupt variations"
the signal is considerably affected when different resolutions are chosen.
C. Signal Loading
C.1 - Load data from signal samples library
# Load of data
relative_file_path = "../../signal_samples/emg_1000_hz_16_bits_solo.h5"
data, header = bsnb.load(relative_file_path, get_header=True)
C.2 - Information from file Header
#get information which is stored inside variables
ch = "CH1" # Channel
sr = header["sampling rate"] # Sampling rate
resolution = header["resolution"][0] # Resolution (number of available bits)
device = header["device"]
C.3 - Store the desired data in an individual variable
#RAW DATA
signal = data[ch]
C.4 - Convert the RAW data to values with a physical meaning (in this case electric voltage | mV)
# Signal Samples Conversion
signal_uv = bsnb.raw_to_phy("EMG", device, signal, resolution, option="mV") # Conversion to mV
C.5 - Generate a time-axis
time = bsnb.generate_time(signal)
D. Pre-Processing
The effect of a bandpass-filter on the signal (power spectrum) is shown in the following images.
D.1 - Presentation of the original signal power spectrum
With this approach it will be possible to understand the frequency content of the collected data and understand where it is located the informational band.
D.2 - Inclusion of some artificial Gaussian noise to the signal
art_signal = signal + random.random(len(signal)) * 0.035 * max(signal)
D.3 - Application of a band-pass filter to remove high-frequency noise-related components above 200 Hz and low-frequency noise below 10 Hz
# [Signal Filtering]
low_cutoff = 10 # Hz
high_cutoff = 200 # Hz
# Application of the signal to the filter.
signal_filtered = bsnb.bandpass(art_signal, low_cutoff, high_cutoff, order=4, fs = sr)
D.4 - Check the new frequency content of the filtered signal
D.5 - Comparison between the original and filtered signal
As it can be seen in the power spectrum, most reduction takes place in the frequencies above the cutoff frequency of 200 Hz.
For more information on signal filtering, see
Jupyter Notebook
entitled
"Digital Filtering - A Fundamental Pre-Processing Step"
.
E. Event Detection
For the detection of muscular activations, a very simple double-threshold algorithm is defined in the following topics.E.1 - Signal rectification
# [Signal Rectification]
rect_signal = absolute(signal_filtered)
E.2 - Envelope Determination
# Smoothing level [Size of sliding window]
smoothing_level_perc = 20 # Percentage.
smoothing_level = int((smoothing_level_perc / 100) * sr)
#Smooth the signal
signal_smooth = bsnb.smooth(rect_signal, smoothing_level, window='hanning')
E.3 - Double Threshold definition
The first threshold is defined to detect the
onset
of the muscular activation and the second threshold is defined to detect the
offset
of the muscular activation of the signal:
Threshold 1 = average + standard deviation
Threshold 2 = average
# [Threshold]
avg_signal = average(signal_smooth)
std_signal = std(signal_smooth)
thresh_1 = avg_signal + std_signal #Onset of muscular activation
thresh_2 = avg_signal #Offset of muscular activation